﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using TravisCI.Models;
using System.Collections.Generic;
using System.Text;

namespace TravisCI
{
    public class JobViewModel : AbstractViewModel
    {
        public class JobLogViewModel : AbstractViewModel
        {
            public JobLogViewModel(string text)
            {
                this._text = text;
            }

            private string _text;
            public string Text
            {
                get
                {
                    return _text;
                }
                set
                {
                    if (value != _text)
                    {
                        _text = value;
                        NotifyPropertyChanged("Text");
                    }
                }
            }
        }

        private Job job;

        public JobViewModel(Job job)
        {
            LogLines = new ObservableCollection<JobLogViewModel>();
            UpdateFromJob(job);
        }

        /// <summary>
        /// A parameter that specifies how large a block of text,
        /// or TextItem, should be. Play around with this parameter.
        /// The higher this parameter value, the smaller the number of
        /// TextItems, the lower this parameter value, the larger the
        /// number of TextItems. There is an inversely proportional
        /// relationship. If you have a high number of TextItems, a 
        /// lot of ListItem (therefore TextBlocks) will be created,
        /// and the UI will be slow loading. Empirically, setting this
        /// value to 1500 works reasonably well.
        /// </summary>
        private const int MAX = 1500;

        private void UpdateFromJob(Job job)
        {
            this.job = job;
            ResultColor = GetResultColor(job.Result);
            Id = job.Number;
            Env = job.Env;
            Log = job.Log;
            LogLines.Clear();

            int length = Log.Length;
            string[] tokens = Log.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder sb = new StringBuilder();
            foreach (string token in tokens)
            {
                sb.Append(token.Trim());
                if (sb.Length >= MAX)
                {
                    string text = sb.ToString();
                    LogLines.Add(new JobLogViewModel(text));
                    sb.Length = 0;
                }
                else
                {
                    sb.Append("\r\n");
                }
            }

            if (sb.Length > 0)
            {
                string text = sb.ToString();
                LogLines.Add(new JobLogViewModel(text));
            }
        }

        public ObservableCollection<JobLogViewModel> LogLines { get; private set; }

        private Color _resultColor;
        public Color ResultColor
        {
            get
            {
                return _resultColor;
            }
            set
            {
                if (value != _resultColor)
                {
                    _resultColor = value;
                    NotifyPropertyChanged("ResultColor");
                }
            }
        }

        private Color GetResultColor(string result)
        {
            if (result.Equals(Models.Build.SuccessResult))
            {
                return Colors.Green;
            }
            else if (result.Equals(Models.Build.ErrorResult))
            {
                return Colors.Red;
            }
            else
            {
                return Colors.Yellow;
            }
        }

        private string _id;
        public string Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }

        private string _env;
        public string Env
        {
            get
            {
                return _env;
            }
            set
            {
                if (value != _env)
                {
                    _env = value;
                    NotifyPropertyChanged("Env");
                }
            }
        }

        private string _log;
        public string Log
        {
            get
            {
                return _log;
            }
            set
            {
                if (value != _log)
                {
                    _log = value;
                    NotifyPropertyChanged("Log");
                }
            }
        }

        internal void Refresh()
        {
            this.job.Refresh((newjob) =>
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    this.UpdateFromJob(newjob);
                });
            },
            (ex) =>
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    MessageBox.Show("There was an error refreshing the build data\n" +
                                    "The error was: " + ex.Message);
                });
            });
        }
    }
}